package com.cskaoyan.javase.object._1getclass;

/**
 * 方法声明为：
 * public final native Class<?> getClass();
 * 解释：
 *      1.首先它的访问权限修饰符是public，访问权限问题不用考虑。
 *      2.final修饰它，表示它无法被重写,但是可以被继承。
 *      3.native表示该方法是一个本地方法，指的是Java调用其它语言（主要是C/C++）的实现来完成功能的方法。本地方法不需要方法体，我们也不会考虑它的实现细节。
 *      4. Class<?>是返回值类型，Class是一个类名,属于java.lang包下的一个类,表示该方法需要返回一个Class对象。
 *      其中<?>表示泛型，关于泛型后面会详细讲，这里我们先忽略它，并不影响方法调用结果。
 *      泛型对于Java而言,相当于给Java提供了第二生命.
 *      补充:
 *          Java的泛型,区别于C++的泛型,C++的泛型是真泛型,会影响程序的执行
 *          而Java的泛型由于是在后期被迫加上去的,所以Java的泛型是伪泛型
 *          Java的泛型只影响程序的编译,只存在于编译过程中生效,而不影响程序执行
 *
 *      5.该方法不需要任何参数。
 *
 * 方法的作用:
 *      这个方法的作用就是返回Class对象
 *      当然问题肯定马上就来了:
 *          a.什么是Class对象?
 *          b.Class对象又有什么作用?
 *       学习getClass方法,将上述两个问题作为学习的重点.
 *
 * 1.什么是Class类,什么是Class对象?
 *      类加载: 是JVM了解认识某个类型的过程
 *      从大的步骤来说,分成三步,加载-->连接-->初始化
 *      连接又分成三小步: 验证 --> 准备 --> 解析
 *      于是通过类加载,JVM认识了解了该类型
 *      那么:
 *      如果程序员也希望在程序的运行期间,获取类型信息,怎么办呢?
 *      目前来说,我们是没有办法的,但是这个需求很重要,很正常:
 *          因为只要在运行期间获取某个类的类型信息,那么就可以动态的根据类型信息做出一些操作,比如根据某个类的构造器,创建它的对象,调用它的方法等等.
 *      所以为了满足程序员的这个需求,JVM在类加载某个类的过程中
 *      都会自动在堆上创建一个封装了该类类型的对象,也就是Class对象
 *
 * 2.Class对象的作用
 *      某个类的Class对象,也就是封装了该类类型信息的对象,在程序的运行期间
 *          程序员只要获取该对象,那么就可以动态的获取类型信息,完成一些操作
 *      所以Class对象,也称之为某个类的"运行时类对象"或者"运行时对象"
 *
 * 注意事项(补充,扩展):
 *      1.Class对象是谁创建的,是getClass方法创建的吗?
 *          Class对象是JVM创建的,是JVM在类加载某个类的过程中,自动在堆上创建的,是在类加载的加载阶段完成该操作的
 *          getClass方法它不是创建对象的方法,而是获取该对象的一种手段
 *          为什么这个方法是本地方法? 因为直接去堆上获取某个对象,而不是事先就用引用指向它,这是Java代码做不到的
 *         扩展:
 *          实际开发中,获取Class对象的方式还有其它几种,getClass方法获取Class对象基本不用使用.
 *
 *     2.某个类的Class对象封装了该类的类型信息,而且提供了很多方法来访问这些类型信息
 *       比如:
 *       String getName()
 *           以 String 的形式返回此 Class 对象所表示的实体（类、接口、数组类、基本类型或 void）名称。
 *       String getSimpleName()
 *           返回源代码中给出的底层类的简称。
 *       实际上到JavaSE后半段,Java的高级特效—反射，就是通过获取类型信息(Class对象),然后动态的在程序的运行期间完成一些操作
 *       所以反射说白了,就是Class类API的使用
 *       而且反射的技术,还提供了破解私有的方式,反射可以称之为"为所欲为"
 *       反射是Java框架的基础,是Java能够出现如此多精巧设计的根本原因.
 *
 *     3.某个类的类加载只有一次,所以某个类的Class对象是唯一的,是单独只有一个的
 *          所以相同类型的对象,获取该类型的Class对象,用"=="连接返回true
 *          反之,如果不是相同类型,分别获取类型的Class对象,用"=="连接返回false
 *          所以根据以上特点,在实际开发中,getClass方法更常用于:
 *              比较,判断,两个引用所指向的对象,是不是同种类型的对象
 *          扩展:
 *              关于泛型,今天的学习中,仍然建议大家去掉它,不要看,因为它影响程序的编译.
 *
 *
 *
 * @since 10:06
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Student s = new Student();
        Class stuClazz = s.getClass();
        Student s2 = new Student();
        Class stuClazz2 = s2.getClass();
        // Class对象是唯一的,独一份,"=="比较地址,比较两个引用是否指向同一个对象
        System.out.println(stuClazz == stuClazz2);
        Teacher t = new Teacher();
        Class teacherClazz = t.getClass();
        System.out.println(stuClazz == teacherClazz);
        System.out.println("----------------------");
        System.out.println(judgeType(s, t));
        System.out.println(judgeType(s, s2));
        System.out.println("----------------------");

        // 获取全限定类名
        System.out.println(stuClazz.getName());
        // 获取简单类名(不带包名)
        System.out.println(stuClazz.getSimpleName());
        System.out.println("-----------------------");
        // 使用泛型,会影响编译 Class<? extends Teacher>和Class<? extends Student>不是同种类型,不能用"=="连接
        Class<? extends Teacher> teacher = t.getClass();
        Class<? extends Student> student = s.getClass();
        // System.out.println(teacher == student);
    }

    // 比较,判断,两个引用所指向的对象,是不是同种类型的对象的方法,如果是返回true,如果不是返回false
    // 注意这种判断是非常严格的,必须是完全相同的类型才会返回true,不会考虑其他任何情况
    public static boolean judgeType(Object o1, Object o2) {
        return o1.getClass() == o2.getClass();
    }
}

class Student {
}

class Teacher {
}